import base64
import datetime

import json
import numpy as np
import requests as sys_requests
from celery import task, Task
from celery import shared_task
import pandas as pd
from Library_WEB import settings
from stocksys import models as stocksys_models
import time

from stocksys.views.data_logic import get_month_exchange_time


class DjangoTask(Task):
    def on_success(self, retval, task_id, args, kwargs):
        print('task done: {0}'.format(retval))
        return super(DjangoTask, self).on_success(retval, task_id, args, kwargs)

    def on_failure(self, exc, task_id, args, kwargs, einfo):
        print('task fail, reason: {0}'.format(exc))
        return super(DjangoTask, self).on_failure(exc, task_id, args, kwargs, einfo)


def task_begin(id):
    data_update_task = stocksys_models.DataUpdateTask.objects.get(id=id)
    start_time = datetime.datetime.now()
    data_update_task.update_start_time = start_time
    data_update_task.task_state = True
    data_update_task.task_schedule = 0
    data_update_task.save()
    return start_time


def update_schedule(id, current_schedule, max_schedule, result=None):
    data_update_task = stocksys_models.DataUpdateTask.objects.get(id=id)
    data_update_task.task_schedule = (current_schedule / max_schedule) * 100
    state_info = json.dumps({"state": "success",
                             "current_schedule": (current_schedule / max_schedule) * 100,
                             "info": "success",
                             "color": "danger",
                             })
    data_update_task.task_result = state_info
    if result != None:
        data_update_task.task_result = result
        data_update_task.task_state = True
    data_update_task.save()


def task_end(id, start_time):
    data_update_task = stocksys_models.DataUpdateTask.objects.get(id=id)
    data_update_task.update_end_time = datetime.datetime.now()
    cost_time = get_cost_time(start_time)
    data_update_task.task_cost = cost_time
    data_update_task.task_state = False
    data_update_task.save()


def get_cost_time(start_time):
    cost_time = datetime.datetime.now() - start_time
    minutes = cost_time.seconds // 60
    seconds = cost_time.seconds - minutes * 60
    hours = minutes // 60
    minutes = minutes - hours * 60
    return datetime.datetime.strptime('%s:%s:%s' % (hours, minutes, seconds), "%H:%M:%S")

# ==================================================================================

def serialize_realtime_info(content):
    if len(content) > 32:
        return {
            "name": content[0],  # 名称
            "code": None,  # 代码
            "open": float(content[1]),  # 今日开盘价
            "close": float(content[2]),  # 昨日收盘价
            "current": float(content[3]),  # 当前价
            "high": float(content[4]),  # 今日最高价
            "low": float(content[5]),  # 今日最低价
            "a1_v_": float(content[6]),  # 买1
            "b1_v_": float(content[7]),  # 卖1
            "v_num": float(content[8]),  # 成交量
            "money": float(content[9]),  # 成交额
            "a1_v": float(content[10]),  # 买1量
            "a1_p": float(content[11]),  # 买1
            "a2_v": float(content[12]),  # 买2量
            "a2_p": float(content[13]),  # 买2
            "a3_v": float(content[14]),  # 买3量
            "a3_p": float(content[15]),  # 买3
            "a4_v": float(content[16]),  # 买4量
            "a4_p": float(content[17]),  # 买4
            "a5_v": float(content[18]),  # 买5量
            "a5_p": float(content[19]),  # 买5
            "b1_v": float(content[20]),  # 卖1量
            "b1_p": float(content[21]),  # 卖1
            "b2_v": float(content[22]),  # 卖2量
            "b2_p": float(content[23]),  # 卖2
            "b3_v": float(content[24]),  # 卖3量
            "b3_p": float(content[25]),  # 卖3
            "b4_v": float(content[26]),  # 卖4量
            "b4_p": float(content[27]),  # 卖4
            "b5_v": float(content[28]),  # 卖5量
            "b5_p": float(content[29]),  # 卖5
            "date": content[30],
            "time": content[31],
            "systime": datetime.datetime.now().strftime('%Y-%m-%d'),
        }
    else:
        return {
            "name": 0,  # 名称
            "color": 'waring',  # 名称
            "code": "nan",  # 代码
            "open": 0,  # 今日开盘价
            "close": 0,  # 昨日收盘价
            "current": 0,  # 当前价
            "high": 0,  # 今日最高价
            "low": 0,  # 今日最低价
            "a1_v_": 0,  # 买1
            "b1_v_": 0,  # 卖1
            "v_num": 0,  # 成交量
            "money": 0,  # 成交额
            "a1_v": 0,  # 买1量
            "a1_p": 0,  # 买1
            "a2_v": 0,  # 买2量
            "a2_p": 0,  # 买2
            "a3_v": 0,  # 买3量
            "a3_p": 0,  # 买3
            "a4_v": 0,  # 买4量
            "a4_p": 0,  # 买4
            "a5_v": 0,  # 买5量
            "a5_p": 0,  # 买5
            "b1_v": 0,  # 卖1量
            "b1_p": 0,  # 卖1
            "b2_v": 0,  # 卖2量
            "b2_p": 0,  # 卖2
            "b3_v": 0,  # 卖3量
            "b3_p": 0,  # 卖3
            "b4_v": 0,  # 卖4量
            "b4_p": 0,  # 卖4
            "b5_v": 0,  # 卖5量
            "b5_p": 0,  # 卖5
            "date": datetime.datetime.now().strftime('%Y-%m-%d'),
            "time": datetime.datetime.now().strftime('%H-%i-%S'),
            "systime": datetime.datetime.now().strftime('%Y-%m-%d'),
        }


def get_realtime_stock_content(code):
    head = dict()
    head[
        'User-Agent'] = 'Mozilla/5.0 (Linux; Android 4.1.1; Nexus 7 Build/JRO03D) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.166  Safari/535.19'

    url = "http://hq.sinajs.cn/list=%s" % (code)
    response = sys_requests.get(url=url).content.decode('gbk')
    info = response.split('"')[1].split(',')
    info = serialize_realtime_info(info)
    return info


# ==================================================================================
def stock_report(stock: stocksys_models.Stock, report_param):
    saved_path_template = "%s/data/stock_data/stock_%s_%s.csv"
    start_date, now_date = get_month_exchange_time()
    jqdata_stock_code = "%s.%s" % (stock.stock_code, stock.exchange_abbreviated_name)
    today_path = saved_path_template % (settings.BASE_DIR, jqdata_stock_code, now_date)
    index = None
    close = None
    try:
        data = pd.read_csv(today_path)
        index = data['date'].values
        close = data['close'].values
    except Exception as e:
        return report_param

    def create_figure(index, close):
        if type(index) == type(None) or type(close) == type(None):
            return None
        import matplotlib
        matplotlib.use('Agg')
        import matplotlib.pyplot as plt
        from matplotlib import style
        from io import BytesIO

        style.use('ggplot')
        save_file = BytesIO()
        close_fft = np.fft.fft(close)

        indexf = np.arange(len(np.abs(close_fft) / (len(index) / 2)))
        plt.grid()
        close_fft_normal = np.abs(close_fft) / (len(index) / 2)
        # close_fft_normal_block = close_fft_normal[1:10]
        # indexf_block = indexf[1:10]
        # plt.plot(indexf_block, close_fft_normal_block, 'r-')
        plt.plot(indexf, close_fft_normal, 'g-', label='close')
        plt.savefig(save_file, format='png')
        fft = base64.b64encode(save_file.getvalue()).decode('utf8')
        save_file.close()
        plt.close()
        return fft

    report_param['fft'] = create_figure(index, close)
    return report_param


# =====================计算持仓盈亏===================================================
# 当日盈亏
def get_open_intrest_profit_and_loss_a_day(open_interest_stock: stocksys_models.OpenInterests.stock):
    exchange = open_interest_stock.stock
    stock_code = "%s%s" % (exchange.exchange_address.stock_sina_name, exchange.code)
    stock_info = get_realtime_stock_content(stock_code)
    return (stock_info['current'] - stock_info['close']) * open_interest_stock.number

# 持仓盈亏
def get_open_intrest_profit_and_loss(open_interest_stock: stocksys_models.OpenInterests):
    exchange = open_interest_stock.stock.stock
    stock_code = "%s%s" % (exchange.exchange_address.stock_sina_name, exchange.code)
    stock_info = get_realtime_stock_content(stock_code)
    return (stock_info['current'] - open_interest_stock.price) * open_interest_stock.number


# ================================================================================
# 判断是否为工作日,工作日返回True，非工作日返回False
def workDay():
    '''
    交易时间
    :return:
    '''
    workTime = ['09:00:00', '15:00:00']
    dayOfWeek = datetime.datetime.now().weekday()
    # dayOfWeek = datetime.today().weekday()
    beginWork = datetime.datetime.now().strftime("%Y-%m-%d") + ' ' + workTime[0]
    endWork = datetime.datetime.now().strftime("%Y-%m-%d") + ' ' + workTime[1]
    beginWorkSeconds = time.time() - time.mktime(time.strptime(beginWork, '%Y-%m-%d %H:%M:%S'))
    endWorkSeconds = time.time() - time.mktime(time.strptime(endWork, '%Y-%m-%d %H:%M:%S'))
    if (int(dayOfWeek) in range(5)) and int(beginWorkSeconds) > 0 > int(endWorkSeconds):
        return True
    else:
        return False


# 判断工作时间的函数
def onMarketOpen():
    '''
    盘中
    :return:
    '''
    morningTime = ['09:32:00', '11:30:00']  # 早盘
    afternoonTime = ['13:30:00', '15:00:00']  # 午盘
    dayOfWeek = datetime.datetime.now().weekday()  # 周几

    # 早盘开始时间
    morningBeginWork = datetime.datetime.now().strftime("%Y-%m-%d") + ' ' + morningTime[0]
    morningEndWork = datetime.datetime.now().strftime("%Y-%m-%d") + ' ' + morningTime[1]
    morningBeginWorkSeconds = time.time() - time.mktime(time.strptime(morningBeginWork, '%Y-%m-%d %H:%M:%S'))
    morningEndWorkSeconds = time.time() - time.mktime(time.strptime(morningEndWork, '%Y-%m-%d %H:%M:%S'))

    # 午盘开始时间
    afternoonBeginWork = datetime.datetime.now().strftime("%Y-%m-%d") + ' ' + afternoonTime[0]
    afternoonEndWork = datetime.datetime.now().strftime("%Y-%m-%d") + ' ' + afternoonTime[1]
    afternoonBeginWorkSeconds = time.time() - time.mktime(time.strptime(afternoonBeginWork, '%Y-%m-%d %H:%M:%S'))
    afternoonEndWorkSeconds = time.time() - time.mktime(time.strptime(afternoonEndWork, '%Y-%m-%d %H:%M:%S'))

    if (int(dayOfWeek) in range(5)):
        if (int(morningBeginWorkSeconds) > 0 > int(morningEndWorkSeconds)) or (
                int(afternoonBeginWorkSeconds) > 0 > int(afternoonEndWorkSeconds)):
            return True
    return False


def beforeMarketOpen():
    '''
    盘前
    :return:
    '''
    workTime = ['09:30:30', '09:31:00']
    dayOfWeek = datetime.datetime.now().weekday()
    # dayOfWeek = datetime.today().weekday()
    beginWork = datetime.datetime.now().strftime("%Y-%m-%d") + ' ' + workTime[0]
    endWork = datetime.datetime.now().strftime("%Y-%m-%d") + ' ' + workTime[1]
    beginWorkSeconds = time.time() - time.mktime(time.strptime(beginWork, '%Y-%m-%d %H:%M:%S'))
    endWorkSeconds = time.time() - time.mktime(time.strptime(endWork, '%Y-%m-%d %H:%M:%S'))
    if (int(dayOfWeek) in range(5)) and int(beginWorkSeconds) > 0 > int(endWorkSeconds):
        return True
    else:
        return False


def onMarketOpenWork():
    '''
    盘中
    :return:
    '''
    morningTime = ['09:31:00', '11:30:00']  # 早盘
    afternoonTime = ['13:30:00', '15:00:00']  # 午盘
    dayOfWeek = datetime.datetime.now().weekday()  # 周几

    # 早盘开始时间
    morningBeginWork = datetime.datetime.now().strftime("%Y-%m-%d") + ' ' + morningTime[0]
    morningEndWork = datetime.datetime.now().strftime("%Y-%m-%d") + ' ' + morningTime[1]
    morningBeginWorkSeconds = time.time() - time.mktime(time.strptime(morningBeginWork, '%Y-%m-%d %H:%M:%S'))
    morningEndWorkSeconds = time.time() - time.mktime(time.strptime(morningEndWork, '%Y-%m-%d %H:%M:%S'))

    # 午盘开始时间
    afternoonBeginWork = datetime.datetime.now().strftime("%Y-%m-%d") + ' ' + afternoonTime[0]
    afternoonEndWork = datetime.datetime.now().strftime("%Y-%m-%d") + ' ' + afternoonTime[1]
    afternoonBeginWorkSeconds = time.time() - time.mktime(time.strptime(afternoonBeginWork, '%Y-%m-%d %H:%M:%S'))
    afternoonEndWorkSeconds = time.time() - time.mktime(time.strptime(afternoonEndWork, '%Y-%m-%d %H:%M:%S'))

    if (int(dayOfWeek) in range(5)):
        if (int(morningBeginWorkSeconds) > 0 > int(morningEndWorkSeconds)) or (
                int(afternoonBeginWorkSeconds) > 0 > int(afternoonEndWorkSeconds)):
            return True
    return False
